package compile.processor;

import javax.annotation.processing.Messager;
import javax.lang.model.element.*;
import javax.lang.model.util.ElementScanner8;
import javax.tools.Diagnostic;
import java.util.EnumSet;

public class NameChecker {

    private NameCheckScanner scanner = new NameCheckScanner();
    private Messager messager;

    public NameChecker(Messager messager) {
        this.messager = messager;
    }

    public void check(Element element) {
        scanner.scan(element);
    }

    private class NameCheckScanner extends ElementScanner8<Void, Void> {
        @Override
        public Void visitVariable(VariableElement e, Void aVoid) {
            ElementKind kind = e.getKind();
            if(kind == ElementKind.ENUM_CONSTANT || e.getConstantValue() != null || isConstant(e))
                checkAllCap(e);
            else
                checkCamelCase(e, false);
            return super.visitVariable(e, aVoid);
        }

        @Override
        public Void visitType(TypeElement e, Void aVoid) {
            checkCamelCase(e, true);
            return super.visitType(e, aVoid);
        }

        @Override
        public Void visitExecutable(ExecutableElement e, Void aVoid) {
            checkCamelCase(e, false);
            return super.visitExecutable(e, aVoid);
        }

        /**
         * 是否是常量
         * @param e
         * @return
         */
        private boolean isConstant(Element e) {
            if(e.getEnclosingElement().getKind() == ElementKind.INTERFACE || // 在接口中定义
                    (e.getKind() == ElementKind.FIELD // 字段，并且是 public static final
                            && e.getModifiers().containsAll(EnumSet.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL))))
                return true;
            return false;
        }


        /**
         * 检查全部是大写
         * @param e
         */
        private void checkAllCap(Element e) {
            String name = e.getSimpleName().toString();
            if(name == null || name.length() == 0)
                return;
            char[] chars = name.toCharArray();
            if(!Character.isUpperCase(chars[0])) {
                messager.printMessage(Diagnostic.Kind.WARNING, "常量[" + name + "]必须以大写字母开头", e);
                return;
            }
            for (int i = 1; i < chars.length; i++) {
                if(Character.isUpperCase(chars[i]) || chars[i] == '_')
                    continue;
                else {
                    messager.printMessage(Diagnostic.Kind.WARNING, "常量[" + name + "]必须全部为大写字母或下划线", e);
                    return;
                }
            }
        }

        /**
         * 检查驼峰命名
         * @param e
         * @param upStart 是否要以大写开头
         */
        private void checkCamelCase(Element e, boolean upStart) {
            String name = e.getSimpleName().toString();
            if(name == null || name.length() == 0)
                return;
            char[] chars = name.toCharArray();
            boolean prevUp = false;
            if(upStart) {
                if(!Character.isUpperCase(chars[0])) {
                    messager.printMessage(Diagnostic.Kind.WARNING, "变量名[" + name + "]， 首字母要大写", e);
                    return;
                }
                prevUp = true;
            }
            for (int i = 1; i < chars.length; i++) {
                if(Character.isUpperCase(chars[i])) {
                    if(prevUp) {
                        messager.printMessage(Diagnostic.Kind.WARNING, "变量名[" + name + "]， 不符合驼峰命名规范，检测到连续两个大写", e);
                        return;
                    }
                    prevUp = true;
                } else if(Character.isLowerCase(chars[i])){
                    prevUp = false;
                }
            }
        }
    }
}
